Imports System.Xml

Namespace WoWArmoryParser
  Public Class ArmoryParser

    Public Shared Function GetCharacter(ByVal Realm As String, ByVal Name As String, ByVal Region As RegionEnum) As Character
      Dim ch As New Character

      Dim path As String
      Dim doc As XmlReader
      Dim settings As New XmlReaderSettings()

      Try

        path = GetRegionPath(Region) & "/character-sheet.xml"
        doc = GetStream(path, Realm, Name)

        ch.Region = Region
        ch.IsValid = False
        Do While doc.Read
          If doc.NodeType = XmlNodeType.Element Then
            If doc.LocalName = "characterInfo" Then
              Using chInfo As XmlReader = doc.ReadSubtree
                While chInfo.Read
                  If chInfo.LocalName = "character" Then
                    'Process the character basic stats
                    Call GetEl_Character(chInfo, ch, Name, Realm, Region)
                  ElseIf chInfo.LocalName = "characterTab" Then
                    'Process the character tab information
                    Call GetEl_CharTab(chInfo, ch)
                  End If
                End While
                chInfo.Close()
              End Using
            End If

          End If
        Loop
        doc.Close()

        'Reps
        path = GetRegionPath(Region) & "/character-reputation.xml"
        doc = GetStream(path, Realm, Name)

        Do While doc.Read
          If doc.NodeType = XmlNodeType.Element Then
            '<reputationTab />
            If doc.LocalName = "factionCategory" AndAlso (doc.GetAttribute("key") = "horde" OrElse doc.GetAttribute("key") = "alliance") Then ch.GroupedReputations.Faction = GetRepsList(ch, doc.GetAttribute("name"), doc)
            If doc.LocalName = "factionCategory" AndAlso (doc.GetAttribute("key") = "hordeforces" OrElse doc.GetAttribute("key") = "allianceforces") Then ch.GroupedReputations.BattleGrounds = GetRepsList(ch, doc.GetAttribute("name"), doc)
            If doc.LocalName = "factionCategory" AndAlso doc.GetAttribute("key") = "outland" Then ch.GroupedReputations.Outland = GetRepsList(ch, doc.GetAttribute("name"), doc)
            If doc.LocalName = "factionCategory" AndAlso doc.GetAttribute("key") = "shattrathcity" Then ch.GroupedReputations.ShattrathCity = GetRepsList(ch, doc.GetAttribute("name"), doc)
            If doc.LocalName = "factionCategory" AndAlso doc.GetAttribute("key") = "steamwheedlecartel" Then ch.GroupedReputations.SteamwheedleCartel = GetRepsList(ch, doc.GetAttribute("name"), doc)
            If doc.LocalName = "factionCategory" AndAlso doc.GetAttribute("key") = "zother" Then ch.GroupedReputations.Others = GetRepsList(ch, doc.GetAttribute("name"), doc)
          End If
        Loop
        doc.Close()
      Catch ex As System.Net.WebException
        ch.IsValid = False
        If (ex.Message.Contains("503") Or ex.Message.Contains("500")) Then
          Throw ex
        End If
      Catch ex As Exception
        ch.IsValid = False
      End Try
      Return ch
    End Function

    Public Shared Function GetGuild(ByVal Realm As String, ByVal Name As String, ByVal Region As RegionEnum) As Guild
      Dim g As New Guild
      Dim path As String = GetRegionPath(Region) & "/guild-info.xml"
      Using doc As XmlReader = GetStream(path, Realm, Name)

        g.Region = Region
        Do While doc.Read
          If doc.NodeType = XmlNodeType.Element Then
            If doc.LocalName = "guild" Then
              g.BattleGroup = doc.GetAttribute("battleGroup")
              g.Realm = doc.GetAttribute("realm")
              g.Name = doc.GetAttribute("name")
            End If
            If doc.LocalName = "character" Then
              Dim member As New GuildMember(doc.GetAttribute("name"), g.Realm, Region)
              With member
                .CharClass = GetClassEnumFromString(doc.GetAttribute("class"))
                .Gender = GetGenderEnumFromString(doc.GetAttribute("gender"))
                .Race = GetRaceEnumFromString(doc.GetAttribute("race"))
                .Level = doc.GetAttribute("level")
                .Rank = doc.GetAttribute("rank")
              End With
              If doc.GetAttribute("rank") = 0 Then g.GuildMaster = member
              g.Members.Add(member)
            End If

          End If
        Loop
      End Using
      Return g
    End Function

    Public Shared Function GetArenaTeam(ByVal Realm As String, ByVal Name As String, ByVal Size As ArenaTeamSizeEnum, ByVal Region As RegionEnum) As ArenaTeam
      Dim at As New ArenaTeam
      Dim path As String = GetRegionPath(Region) & "/team-info.xml"
      Using doc As XmlReader = GetStream(path, Realm, Name, Size)
        'at.Realm = Realm
        at.Region = Region
        Do While doc.Read
          If doc.NodeType = XmlNodeType.Element Then
            If doc.LocalName = "arenaTeam" Then
              at.BattleGroup = doc.GetAttribute("battleGroup")
              at.Faction = CType(doc.GetAttribute("factionID"), Integer)
              at.Name = doc.GetAttribute("name")
              at.Ranking = doc.GetAttribute("ranking")
              at.Rating = doc.GetAttribute("rating")
              at.Size = CType(doc.GetAttribute("size"), Integer)
              at.Realm = doc.GetAttribute("realm")
              With at.GamesInWeek
                .Played = doc.GetAttribute("gamesPlayed")
                .Wins = doc.GetAttribute("gamesWon")
              End With
              With at.GamesInSeason
                .Played = doc.GetAttribute("seasonGamesPlayed")
                .Wins = doc.GetAttribute("seasonGamesWon")
              End With
            ElseIf doc.LocalName = "emblem" Then
              With at.Emblem
                .BackgroundColor = doc.GetAttribute("background")
                .BorderColor = doc.GetAttribute("borderColor")
                .IconColor = doc.GetAttribute("iconColor")
                .BorderStyle = doc.GetAttribute("borderStyle")
                .IconStyle = doc.GetAttribute("iconStyle")
              End With
            ElseIf doc.LocalName = "character" Then
              Dim member As New ArenaMember(doc.GetAttribute("name"), Realm, Region)
              With member
                .CharClass = GetClassEnumFromString(doc.GetAttribute("class"))
                .Gender = GetGenderEnumFromString(doc.GetAttribute("gender"))
                .Race = GetRaceEnumFromString(doc.GetAttribute("race"))
                .Rank = doc.GetAttribute("teamRank")
                .GuildName = doc.GetAttribute("guild")
                With .GamesInWeek
                  .Played = doc.GetAttribute("gamesPlayed")
                  .Wins = doc.GetAttribute("gamesWon")
                End With
                With .GamesInSeason
                  .Played = doc.GetAttribute("seasonGamesPlayed")
                  .Wins = doc.GetAttribute("seasonGamesWon")
                End With
              End With
              If doc.GetAttribute("teamRank") = 0 Then at.Leader = member
              at.Members.Add(member)
            End If
          End If
        Loop
      End Using
      Return at
    End Function

    Public Shared Function GetItem(ByVal ID As Integer) As Item
      Dim i As New Item
      Dim path As String = GetRegionPath(RegionEnum.USA) & "/item-info.xml"

      Using doc As XmlReader = GetStream(path, ID)
        Do While doc.Read
          If doc.NodeType = XmlNodeType.Element Then
            If doc.LocalName = "item" Then
              If doc.MoveToAttribute("id") AndAlso doc.ReadContentAsInt = ID Then
                i.ID = ID
                If doc.MoveToAttribute("icon") Then i.Icon = doc.ReadContentAsString
                If doc.MoveToAttribute("level") Then i.Level = doc.ReadContentAsInt
                If doc.MoveToAttribute("name") Then i.Name = doc.ReadContentAsString
                If doc.MoveToAttribute("quality") Then i.Quality = doc.ReadContentAsInt
                i.IsValid = True
              End If
            End If
          End If
        Loop
        doc.Close()
      End Using
      Return i
    End Function

#Region "Connectivity Functions"
    Protected Friend Shared Function GetRegionPath(ByVal Region As RegionEnum) As String
      Dim path As String = ""
      Select Case Region
        Case RegionEnum.Europe
          path = "http://eu.wowarmory.com"
        Case RegionEnum.USA
          path = "http://www.wowarmory.com"
      End Select
      Return path
    End Function

    Protected Shared Function GetStream(ByVal Path As String, ByVal Realm As String, ByVal Name As String) As Xml.XmlReader
      Dim wc As New Net.WebClient
      Dim xtr As Xml.XmlReader

      Dim settings As New XmlReaderSettings
      settings.IgnoreComments = True
      settings.IgnoreWhitespace = True

      wc.QueryString.Add("r", Realm)
      wc.QueryString.Add("n", Name)
      wc.Headers.Add("user-agent", "MSIE 7.0")
      xtr = XmlReader.Create(wc.OpenRead(Path), settings)
      Return xtr
    End Function

    Protected Shared Function GetStream(ByVal Path As String, ByVal ItemID As Integer) As XmlReader
      Dim wc As New Net.WebClient
      Dim xtr As Xml.XmlReader

      Dim settings As New XmlReaderSettings
      settings.IgnoreComments = True
      settings.IgnoreWhitespace = True

      wc.QueryString.Add("i", ItemID)
      wc.Headers.Add("user-agent", "MSIE 7.0")
      xtr = XmlReader.Create(wc.OpenRead(Path), settings)
      Return xtr
    End Function

    Protected Shared Function GetStream(ByVal Path As String, ByVal Realm As String, ByVal Name As String, ByVal Size As ArenaTeamSizeEnum) As Xml.XmlReader
      Dim wc As New Net.WebClient
      Dim xtr As Xml.XmlReader

      Dim settings As New XmlReaderSettings
      settings.IgnoreComments = True
      settings.IgnoreWhitespace = True

      wc.QueryString.Add("r", Realm)
      wc.QueryString.Add("t", Name)
      wc.QueryString.Add("ts", CType(Size, Integer))
      wc.Headers.Add("user-agent", "MSIE 7.0")
      xtr = XmlReader.Create(wc.OpenRead(Path), settings)
      Return xtr
    End Function
#End Region
#Region "XML Parsing Support Methods"
    Protected Shared Sub GetEl_Character(ByRef xml As XmlReader, ByRef ch As Character, ByVal Name As String, ByVal Realm As String, ByVal Region As RegionEnum)

      Dim _startDepth As Integer
      _startDepth = xml.Depth

      If xml.MoveToAttribute("name") AndAlso xml.ReadContentAsString().ToLower = Name.ToLower Then ch.Name = xml.GetAttribute("name")
      If xml.MoveToAttribute("realm") Then ch.Realm = xml.ReadContentAsString
      If xml.MoveToAttribute("class") Then ch.CharClass = GetClassEnumFromString(xml.ReadContentAsString)
      If xml.MoveToAttribute("gender") Then ch.Gender = GetGenderEnumFromString(xml.ReadContentAsString)
      If xml.MoveToAttribute("guildName") Then ch.GuildName = xml.ReadContentAsString
      If xml.MoveToAttribute("level") Then ch.Level = xml.ReadContentAsInt
      If xml.MoveToAttribute("race") Then ch.Race = GetRaceEnumFromString(xml.ReadContentAsString)
      If xml.MoveToAttribute("lastModified") Then ch.LastUpdate = DateTime.Parse(xml.ReadContentAsString)
      If xml.MoveToAttribute("factionId") Then ch.Faction = xml.ReadContentAsInt

      xml.MoveToElement()

      Using chSub As XmlReader = xml.ReadSubtree
        Do While chSub.Read
          If chSub.NodeType = XmlNodeType.Element AndAlso chSub.LocalName = "arenaTeams" Then
            Using teams As XmlReader = chSub.ReadSubtree
              Do While teams.Read
                If xml.LocalName = "arenaTeam" Then
                  Call GetEl_ArenaTeam(teams, ch, Realm, Region)
                End If
              Loop
              teams.Close()
            End Using
          End If
        Loop
        chSub.Close()
      End Using
    End Sub

    Protected Shared Sub GetEl_ArenaTeam(ByRef xml As XmlReader, ByRef ch As Character, ByVal Realm As String, ByVal Region As RegionEnum)
      Select Case xml.GetAttribute("size")
        Case "2"
          ch.Team2v2Name = xml.GetAttribute("name")
          Call GetAttribs_ArenaTeam(xml, ch.Team2v2, Realm, Region)
        Case "3"
          ch.Team3v3Name = xml.GetAttribute("name")
          Call GetAttribs_ArenaTeam(xml, ch.Team3v3, Realm, Region)
        Case "5"
          ch.Team5v5Name = xml.GetAttribute("name")
          Call GetAttribs_ArenaTeam(xml, ch.Team5v5, Realm, Region)
      End Select
    End Sub
    Protected Shared Sub GetAttribs_ArenaTeam(ByRef xml As XmlReader, ByRef team As ArenaTeam, ByVal Realm As String, ByVal Region As RegionEnum)

      If xml.MoveToAttribute("battleGroup") Then team.BattleGroup = xml.ReadContentAsString
      If xml.MoveToAttribute("factionId") Then team.Faction = xml.ReadContentAsInt

      If xml.MoveToAttribute("gamesPlayed") Then team.GamesInWeek.Played = xml.ReadContentAsInt
      If xml.MoveToAttribute("gamesWon") Then team.GamesInWeek.Wins = xml.ReadContentAsInt

      If xml.MoveToAttribute("name") Then team.Name = xml.ReadContentAsString
      If xml.MoveToAttribute("ranking") Then team.Ranking = xml.ReadContentAsInt
      If xml.MoveToAttribute("rating") Then team.Rating = xml.ReadContentAsInt
      If xml.MoveToAttribute("realm") Then team.Realm = xml.ReadContentAsString

      If xml.MoveToAttribute("seasonGamesPlayed") Then team.GamesInSeason.Played = xml.ReadContentAsInt
      If xml.MoveToAttribute("seasonGamesWon") Then team.GamesInSeason.Wins = xml.ReadContentAsInt

      xml.MoveToElement()

      Using teamBranch As XmlReader = xml.ReadSubtree
        Do While teamBranch.Read
          If teamBranch.LocalName = "emblem" Then
            If teamBranch.MoveToAttribute("background") Then team.Emblem.BackgroundColor = teamBranch.ReadContentAsString
            If teamBranch.MoveToAttribute("borderColor") Then team.Emblem.BorderColor = teamBranch.ReadContentAsString
            If teamBranch.MoveToAttribute("borderStyle") Then team.Emblem.BorderStyle = teamBranch.ReadContentAsInt
            If teamBranch.MoveToAttribute("iconColor") Then team.Emblem.IconColor = teamBranch.ReadContentAsString
            If teamBranch.MoveToAttribute("iconStyle") Then team.Emblem.IconStyle = teamBranch.ReadContentAsInt
          ElseIf teamBranch.LocalName = "members" Then
            Using member As XmlReader = teamBranch.ReadSubtree
              Do While member.Read
                If member.LocalName = "character" Then
                  Dim atChar As ArenaMember = New ArenaMember("unknown", Realm, Region)

                  If xml.MoveToAttribute("classId") Then atChar.CharClass = xml.ReadContentAsInt

                  If xml.MoveToAttribute("gamesPlayed") Then atChar.GamesInWeek.Played = xml.ReadContentAsInt
                  If xml.MoveToAttribute("gamesWon") Then atChar.GamesInWeek.Wins = xml.ReadContentAsInt

                  If xml.MoveToAttribute("genderId") Then atChar.Gender = xml.ReadContentAsInt
                  If xml.MoveToAttribute("guild") Then atChar.GuildName = xml.ReadContentAsString
                  If xml.MoveToAttribute("name") Then atChar.Name = xml.ReadContentAsString
                  If xml.MoveToAttribute("raceId") Then atChar.Race = xml.ReadContentAsInt

                  If xml.MoveToAttribute("seasonGamesPlayed") Then atChar.GamesInSeason.Played = xml.ReadContentAsInt
                  If xml.MoveToAttribute("seasonGamesWon") Then atChar.GamesInSeason.Wins = xml.ReadContentAsInt

                  If xml.MoveToAttribute("teamRank") Then atChar.Rank = xml.ReadContentAsInt

                  If atChar.Name <> "unknown" AndAlso atChar.Name <> "" Then
                    team.Members.Add(atChar)

                    If atChar.Rank = 0 Then team.Leader = atChar

                  End If
                End If
              Loop
              member.Close()
            End Using
          End If
        Loop
        teamBranch.Close()
      End Using

    End Sub


    Protected Shared Sub GetEl_CharTab(ByRef xml As XmlReader, ByRef ch As Character)
      ch.IsValid = True

      Using chTabBranch As XmlReader = xml.ReadSubtree
        Do While chTabBranch.Read

          If chTabBranch.NodeType = XmlNodeType.Element Then
            If chTabBranch.LocalName = "talentSpec" Then
              '<talentSpec />
              Dim t1 As Integer, t2 As Integer, t3 As Integer
              If chTabBranch.MoveToAttribute("treeOne") Then t1 = chTabBranch.ReadContentAsInt
              If chTabBranch.MoveToAttribute("treeTwo") Then t2 = chTabBranch.ReadContentAsInt
              If chTabBranch.MoveToAttribute("treeThree") Then t3 = chTabBranch.ReadContentAsInt
              ch.TalentSpec = New TalentSpec(t1, t2, t3)
              '<professions />
            ElseIf chTabBranch.LocalName = "lifetimehonorablekills" Then
              If chTabBranch.MoveToAttribute("value") Then ch.LifeTimeHonorableKills = chTabBranch.ReadContentAsInt
              '<arenaTeam battleGroup="Ruin" faction="Horde" factionId="1" gamesPlayed="3" gamesWon="3" lastSeasonRanking="0" name="Chester Bennington" ranking="34" rating="2154" realm="Hakkar" realmUrl="b=Ruin&amp;r=Hakkar&amp;ts=2&amp;t=Chester+Bennington&amp;ff=realm&amp;fv=Hakkar&amp;select=Chester+Bennington" seasonGamesPlayed="191" seasonGamesWon="124" size="2" url="r=Hakkar&amp;ts=2&amp;t=Chester+Bennington&amp;select=Chester+Bennington">
            ElseIf chTabBranch.LocalName = "professions" Then
              ch.Skills.Professions = GetSkillList(chTabBranch)
              '<characterBars />
            ElseIf chTabBranch.LocalName = "health" Then
              Dim cb As New CharacterBar
              cb.Type = BarType.Health
              If chTabBranch.MoveToAttribute("effective") Then cb.Total = chTabBranch.ReadContentAsInt
              ch.HealthBar = cb
            ElseIf chTabBranch.LocalName = "secondBar" Then
              Dim cb As New CharacterBar
              If chTabBranch.MoveToAttribute("effective") Then cb.Total = chTabBranch.ReadContentAsInt
              Dim type As String = ""
              If chTabBranch.MoveToAttribute("type") Then type = chTabBranch.ReadContentAsString
              Select Case type
                Case "m" : cb.Type = BarType.Mana
                Case "e" : cb.Type = BarType.Energy
                Case "r" : cb.Type = BarType.Rage
                Case "p" : cb.Type = BarType.RunicPower
                Case Else : Throw New SecondBarTypeNotValidException
              End Select
              ch.SecondBar = cb
            ElseIf chTabBranch.LocalName = "baseStats" Then
              '<baseStats />
              Call GetStatList_BaseStats(chTabBranch, ch)
            ElseIf chTabBranch.LocalName = "resistances" Then
              '<resistances />
              Call GetStatList_Resists(chTabBranch, ch)
            ElseIf chTabBranch.LocalName = "spell" Then
              Call GetStatList_SpellSkills(chTabBranch, ch)
            ElseIf chTabBranch.LocalName = "melee" Then
              Call GetStatList_MeleeSkills(chTabBranch, ch)
            ElseIf chTabBranch.LocalName = "ranged" Then
              Call GetStatList_RangedSkills(chTabBranch, ch)
            ElseIf chTabBranch.LocalName = "defenses" Then
              Call GetStatList_DefenseSkills(chTabBranch, ch)
            ElseIf chTabBranch.LocalName = "items" Then
              Using itm As XmlReader = chTabBranch.ReadSubtree
                While itm.Read
                  If itm.LocalName = "item" Then
                    Dim slot As EquipSlotEnum
                    Dim id As Integer

                    If itm.MoveToAttribute("slot") Then slot = itm.ReadContentAsInt
                    If itm.MoveToAttribute("id") Then id = itm.ReadContentAsInt

                    ch.Equip.ItemID(slot) = id
                  End If
                End While
                itm.Close()
              End Using
            End If
          End If
        Loop
        chTabBranch.Close()
      End Using
    End Sub


    Protected Shared Function GetRepsList(ByRef ch As Character, ByVal FactionCategory As String, ByVal xml As XmlReader) As GroupedReputationCollection
      Dim list As New GroupedReputationCollection(FactionCategory)
      If xml.NodeType = XmlNodeType.Element Then
        Using reps As XmlReader = xml.ReadSubtree
          Do While reps.Read
            If reps.NodeType = XmlNodeType.Element AndAlso reps.LocalName = "faction" Then 'Not reps.LocalName = "factionCategory" Then
              Dim re As New Reputation
              With re
                .Key = reps.GetAttribute("key")
                .Name = reps.GetAttribute("name")
                .Value = reps.GetAttribute("reputation")
              End With
              list.Add(re.Key, re)
              ch.Reputations.Add(re.Key, re)
            End If
          Loop
        End Using
      End If
      Return list
    End Function

    Protected Shared Function GetSkillList(ByRef xml As XmlReader) As SkillCollection
      Dim list As New SkillCollection
      Using skillz As XmlReader = xml.ReadSubtree
        Do While skillz.Read
          If skillz.NodeType = XmlNodeType.Element AndAlso skillz.LocalName = "skill" Then
            Dim sk As New Skill
            With sk
              .Key = skillz.GetAttribute("key")
              .Max = skillz.GetAttribute("max")
              .Name = skillz.GetAttribute("name")
              .Value = skillz.GetAttribute("value")
            End With
            list.Add(sk)
          End If
        Loop
        skillz.Close()
      End Using
      Return list
    End Function

    Protected Shared Sub GetStatList_BaseStats(ByRef xml As XmlReader, ByRef ch As Character)
      Using stat As XmlReader = xml.ReadSubtree
        Do While stat.Read
          If stat.LocalName = "strength" AndAlso stat.MoveToAttribute("effective") Then
            ch.BaseStats.Strength = stat.ReadContentAsInt
          ElseIf stat.LocalName = "agility" AndAlso stat.MoveToAttribute("effective") Then
            ch.BaseStats.Agility = stat.ReadContentAsInt
          ElseIf stat.LocalName = "stamina" AndAlso stat.MoveToAttribute("effective") Then
            ch.BaseStats.Stamina = stat.ReadContentAsInt
          ElseIf stat.LocalName = "intellect" AndAlso stat.MoveToAttribute("effective") Then
            ch.BaseStats.Intellect = stat.ReadContentAsInt
          ElseIf stat.LocalName = "spirit" AndAlso stat.MoveToAttribute("effective") Then
            ch.BaseStats.Spirit = stat.ReadContentAsInt
          ElseIf stat.LocalName = "armor" AndAlso stat.MoveToAttribute("effective") Then
            ch.BaseStats.Armor = stat.ReadContentAsInt
          End If
        Loop
        stat.Close()
      End Using
    End Sub
    Protected Shared Sub GetStatList_Resists(ByRef xml As XmlReader, ByRef ch As Character)
      Using res As XmlReader = xml.ReadSubtree
        Do While res.Read
          If res.LocalName = "arcane" AndAlso res.MoveToAttribute("value") Then ch.Resistances.ArcaneRes = res.ReadContentAsInt
          If res.LocalName = "fire" AndAlso res.MoveToAttribute("value") Then ch.Resistances.FireRes = res.ReadContentAsInt
          If res.LocalName = "frost" AndAlso res.MoveToAttribute("value") Then ch.Resistances.FrostRes = res.ReadContentAsInt
          If res.LocalName = "holy" AndAlso res.MoveToAttribute("value") Then ch.Resistances.HolyRes = res.ReadContentAsInt
          If res.LocalName = "nature" AndAlso res.MoveToAttribute("value") Then ch.Resistances.NatureRes = res.ReadContentAsInt
          If res.LocalName = "shadow" AndAlso res.MoveToAttribute("value") Then ch.Resistances.ShadowRes = res.ReadContentAsInt
        Loop
        res.Close()
      End Using
    End Sub
    Protected Shared Sub GetStatList_MeleeSkills(ByRef xml As XmlReader, ByRef ch As Character)
      Using melee As XmlReader = xml.ReadSubtree
        Do While melee.Read
          If melee.LocalName = "mainHandWeaponSkill" Then
            If melee.MoveToAttribute("rating") Then ch.Melee.MainHand.Skill.Rating = melee.ReadContentAsInt
            If melee.MoveToAttribute("value") Then ch.Melee.MainHand.Skill.Value = melee.ReadContentAsInt
          End If
          If melee.LocalName = "mainHandDamage" Then
            If melee.MoveToAttribute("dps") Then
              ch.Melee.MainHand.Damage.DPS = melee.ReadContentAsDouble
            ElseIf melee.MoveToAttribute("max") Then
              ch.Melee.MainHand.Damage.Max = melee.ReadContentAsInt
            ElseIf melee.MoveToAttribute("min") Then
              ch.Melee.MainHand.Damage.Min = melee.ReadContentAsInt
            ElseIf melee.MoveToAttribute("percent") Then
              ch.Melee.MainHand.Damage.Percent = melee.ReadContentAsDouble
            ElseIf melee.MoveToAttribute("speed") Then
              ch.Melee.MainHand.Damage.Speed = melee.ReadContentAsDouble
            End If
          End If
          If melee.LocalName = "mainHandSpeed" Then
            If melee.MoveToAttribute("hastePercent") Then
              ch.Melee.MainHand.Speed.HastePercent = melee.ReadContentAsDouble
            ElseIf melee.MoveToAttribute("hasteRating") Then
              ch.Melee.MainHand.Speed.HasteRating = melee.ReadContentAsInt
            ElseIf melee.MoveToAttribute("value") Then
              ch.Melee.MainHand.Speed.Value = melee.ReadContentAsDouble
            End If
          End If
          If melee.LocalName = "offHandWeaponSkill" Then
            If melee.MoveToAttribute("rating") Then ch.Melee.OffHand.Skill.Rating = melee.ReadContentAsInt
            If melee.MoveToAttribute("value") Then ch.Melee.OffHand.Skill.Value = melee.ReadContentAsInt
          End If
          If melee.LocalName = "offHandDamage" Then
            If melee.MoveToAttribute("dps") Then
              ch.Melee.OffHand.Damage.DPS = melee.ReadContentAsDouble
            ElseIf melee.MoveToAttribute("max") Then
              ch.Melee.OffHand.Damage.Max = melee.ReadContentAsInt
            ElseIf melee.MoveToAttribute("min") Then
              ch.Melee.OffHand.Damage.Min = melee.ReadContentAsInt
            ElseIf melee.MoveToAttribute("percent") Then
              ch.Melee.OffHand.Damage.Percent = melee.ReadContentAsDouble
            ElseIf melee.MoveToAttribute("speed") Then
              ch.Melee.OffHand.Damage.Speed = melee.ReadContentAsDouble
            End If
          End If
          If melee.LocalName = "offHandSpeed" Then
            If melee.MoveToAttribute("hastePercent") Then ch.Melee.OffHand.Speed.HastePercent = melee.ReadContentAsDouble
            If melee.MoveToAttribute("hasteRating") Then ch.Melee.OffHand.Speed.HasteRating = melee.ReadContentAsInt
            If melee.MoveToAttribute("value") Then ch.Melee.OffHand.Speed.Value = melee.ReadContentAsDouble
          End If
          If melee.LocalName = "hitRating" Then
            If melee.MoveToAttribute("increasedHitPercent") Then ch.Melee.HitRating.IncreasedHitChance = melee.ReadContentAsDouble
            If melee.MoveToAttribute("value") Then ch.Melee.HitRating.Value = melee.ReadContentAsInt
          End If
          If melee.LocalName = "power" Then
            If melee.MoveToAttribute("base") Then ch.Melee.AttackPower.Base = melee.ReadContentAsInt
            If melee.MoveToAttribute("effective") Then ch.Melee.AttackPower.Effective = melee.ReadContentAsInt
            If melee.MoveToAttribute("increasedDps") Then ch.Melee.AttackPower.IncreasedDPS = melee.ReadContentAsDouble
          End If
          If melee.LocalName = "critChance" Then
            If melee.MoveToAttribute("percent") Then ch.Melee.CritChance.Percent = melee.ReadContentAsDouble
            If melee.MoveToAttribute("plusPercent") Then ch.Melee.CritChance.IncreasedByRating = melee.ReadContentAsDouble
            If melee.MoveToAttribute("rating") Then ch.Melee.CritChance.Rating = melee.ReadContentAsInt
          End If
        Loop
        melee.Close()
      End Using
    End Sub
    Protected Shared Sub GetStatList_RangedSkills(ByRef xml As XmlReader, ByRef ch As Character)
      Using ranged As XmlReader = xml.ReadSubtree
        While ranged.Read
          If ranged.LocalName = "weaponSkill" Then
            If ranged.MoveToAttribute("rating") Then ch.Ranged.Weapon.Skill.Rating = ranged.ReadContentAsInt
            If ranged.MoveToAttribute("value") Then ch.Ranged.Weapon.Skill.Value = ranged.ReadContentAsInt
          End If
          If ranged.LocalName = "damage" Then
            If ranged.MoveToAttribute("dps") Then ch.Ranged.Weapon.Damage.DPS = ranged.ReadContentAsDouble
            If ranged.MoveToAttribute("max") Then ch.Ranged.Weapon.Damage.Max = ranged.ReadContentAsInt
            If ranged.MoveToAttribute("min") Then ch.Ranged.Weapon.Damage.Min = ranged.ReadContentAsInt
            If ranged.MoveToAttribute("percent") Then ch.Ranged.Weapon.Damage.Percent = ranged.ReadContentAsDouble
            If ranged.MoveToAttribute("speed") Then ch.Ranged.Weapon.Damage.Speed = ranged.ReadContentAsDouble
          End If
          If ranged.LocalName = "speed" Then
            If ranged.MoveToAttribute("hastePercent") Then ch.Ranged.Weapon.Speed.HastePercent = ranged.ReadContentAsDouble
            If ranged.MoveToAttribute("hasteRating") Then ch.Ranged.Weapon.Speed.HasteRating = ranged.ReadContentAsInt
            If ranged.MoveToAttribute("value") Then ch.Ranged.Weapon.Speed.Value = ranged.ReadContentAsDouble
          End If
          If ranged.LocalName = "hitRating" Then
            If ranged.MoveToAttribute("increasedHitPercent") Then ch.Ranged.HitRating.IncreasedHitChance = ranged.ReadContentAsDouble
            If ranged.MoveToAttribute("value") Then ch.Ranged.HitRating.Value = ranged.ReadContentAsInt
          End If
          If ranged.LocalName = "power" Then
            If ranged.MoveToAttribute("base") Then ch.Ranged.AttackPower.Base = ranged.ReadContentAsInt
            If ranged.MoveToAttribute("effective") Then ch.Ranged.AttackPower.Effective = ranged.ReadContentAsInt
            If ranged.MoveToAttribute("increasedDps") Then ch.Ranged.AttackPower.IncreasedDPS = ranged.ReadContentAsDouble
          End If
          If ranged.LocalName = "critChance" Then
            If ranged.MoveToAttribute("percent") Then ch.Ranged.CritChance.Percent = ranged.ReadContentAsDouble
            If ranged.MoveToAttribute("plusPercent") Then ch.Ranged.CritChance.IncreasedByRating = ranged.ReadContentAsDouble
            If ranged.MoveToAttribute("rating") Then ch.Ranged.CritChance.Rating = ranged.ReadContentAsInt
          End If
        End While
        ranged.Close()
      End Using
    End Sub
    Protected Shared Sub GetStatList_DefenseSkills(ByRef xml As XmlReader, ByRef ch As Character)
      Using def As XmlReader = xml.ReadSubtree
        Dim defense As DefenseInfo = ch.Defense
        While def.Read
          If def.LocalName = "armor" Then
            If def.MoveToAttribute("base") Then defense.Armor.Base = def.ReadContentAsInt
            If def.MoveToAttribute("effective") Then defense.Armor.Effective = def.ReadContentAsInt
            If def.MoveToAttribute("percent") Then defense.Armor.DamageReductionPercent = def.ReadContentAsDouble
          End If
          If def.LocalName = "defense" Then
            If def.MoveToAttribute("rating") Then defense.Defense.Rating = def.ReadContentAsDouble
            If def.MoveToAttribute("value") Then defense.Defense.Value = def.ReadContentAsDouble
          End If
          If def.LocalName = "dodge" Then
            If def.MoveToAttribute("increasePercent") Then defense.Dodge.IncreasedByRating = def.ReadContentAsDouble
            If def.MoveToAttribute("percent") Then defense.Dodge.Percent = def.ReadContentAsDouble
            If def.MoveToAttribute("rating") Then defense.Dodge.Rating = def.ReadContentAsDouble
          End If
          If def.LocalName = "parry" Then
            If def.MoveToAttribute("increasePercent") Then defense.Parry.IncreasedByRating = def.ReadContentAsDouble
            If def.MoveToAttribute("percent") Then defense.Parry.Percent = def.ReadContentAsDouble
            If def.MoveToAttribute("rating") Then defense.Parry.Rating = def.ReadContentAsDouble
          End If
          If def.LocalName = "block" Then
            If def.MoveToAttribute("increasePercent") Then defense.Block.IncreasedByRating = def.ReadContentAsDouble
            If def.MoveToAttribute("percent") Then defense.Block.Percent = def.ReadContentAsDouble
            If def.MoveToAttribute("rating") Then defense.Block.Rating = def.ReadContentAsDouble
          End If
          If def.LocalName = "resilience" Then
            If def.MoveToAttribute("damagePercent") Then defense.Resilience.DamageReduction = def.ReadContentAsDouble
            If def.MoveToAttribute("hitPercent") Then defense.Resilience.HitReduction = def.ReadContentAsDouble
            If def.MoveToAttribute("value") Then defense.Resilience.Rating = def.ReadContentAsDouble
          End If
        End While
        def.Close()
      End Using
    End Sub
    Protected Shared Sub GetStatList_SpellSkills(ByRef xml As XmlReader, ByRef ch As Character)
      Using spell As XmlReader = xml.ReadSubtree
        Do While spell.Read
          If spell.LocalName = "bonusDamage" Then
            Using dmg As XmlReader = spell.ReadSubtree
              Do While dmg.Read
                If dmg.LocalName = "arcane" AndAlso dmg.MoveToAttribute("value") Then
                  ch.Spell.Arcane.DamageBonus = dmg.ReadContentAsInt
                ElseIf dmg.LocalName = "fire" AndAlso dmg.MoveToAttribute("value") Then
                  ch.Spell.Fire.DamageBonus = dmg.ReadContentAsInt
                ElseIf dmg.LocalName = "frost" AndAlso dmg.MoveToAttribute("value") Then
                  ch.Spell.Frost.DamageBonus = dmg.ReadContentAsInt
                ElseIf dmg.LocalName = "holy" AndAlso dmg.MoveToAttribute("value") Then
                  ch.Spell.Holy.DamageBonus = dmg.ReadContentAsInt
                ElseIf dmg.LocalName = "nature" AndAlso dmg.MoveToAttribute("value") Then
                  ch.Spell.Nature.DamageBonus = dmg.ReadContentAsInt
                ElseIf dmg.LocalName = "shadow" AndAlso dmg.MoveToAttribute("value") Then
                  ch.Spell.Shadow.DamageBonus = dmg.ReadContentAsInt
                End If
              Loop
              dmg.Close()
            End Using
          ElseIf spell.LocalName = "critChance" Then

            Using crit As XmlReader = spell.ReadSubtree
              Do While crit.Read
                If crit.LocalName = "arcane" AndAlso crit.MoveToAttribute("percent") Then
                  ch.Spell.Arcane.CritChance = crit.ReadContentAsDouble
                ElseIf crit.LocalName = "fire" AndAlso crit.MoveToAttribute("percent") Then
                  ch.Spell.Fire.CritChance = crit.ReadContentAsDouble
                ElseIf crit.LocalName = "frost" AndAlso crit.MoveToAttribute("percent") Then
                  ch.Spell.Frost.CritChance = crit.ReadContentAsDouble
                ElseIf crit.LocalName = "holy" AndAlso crit.MoveToAttribute("percent") Then
                  ch.Spell.Holy.CritChance = crit.ReadContentAsDouble
                ElseIf crit.LocalName = "nature" AndAlso crit.MoveToAttribute("percent") Then
                  ch.Spell.Nature.CritChance = crit.ReadContentAsDouble
                ElseIf crit.LocalName = "shadow" AndAlso crit.MoveToAttribute("percent") Then
                  ch.Spell.Shadow.CritChance = crit.ReadContentAsDouble
                End If
              Loop
              crit.Close()
            End Using
            If spell.MoveToAttribute("rating") Then ch.Spell.CritRating = spell.ReadContentAsInt
          ElseIf spell.LocalName = "hitRating" Then
            If spell.MoveToAttribute("increasedHitPercent") Then ch.Spell.HitRating.IncreasedHitChance = spell.ReadContentAsDouble
            If spell.MoveToAttribute("value") Then ch.Spell.HitRating.Value = spell.ReadContentAsInt
          ElseIf spell.LocalName = "bonusHealing" AndAlso spell.MoveToAttribute("value") Then
            ch.Spell.HealingBonus = spell.ReadContentAsInt
          ElseIf spell.LocalName = "penetration" AndAlso spell.MoveToAttribute("value") Then
            ch.Spell.SpellPenetration = spell.ReadContentAsInt
          ElseIf spell.LocalName = "manaRegen" Then
            If spell.MoveToAttribute("casting") Then ch.Spell.ManaRegen.WhileCasting = spell.ReadContentAsDouble
            If spell.MoveToAttribute("notCasting") Then ch.Spell.ManaRegen.WhileNotCasting = spell.ReadContentAsDouble
          End If
        Loop
        spell.Close()
      End Using
    End Sub
    Protected Shared Sub GetStatList_Template(ByRef xml As XmlReader, ByRef ch As Character)
      Using branch As XmlReader = xml.ReadSubtree
        Do While branch.Read
        Loop
        branch.Close()
      End Using
    End Sub
#End Region

    Protected Shared Function GetClassEnumFromString(ByVal Cls As String) As ClassEnum
      Dim res As ClassEnum
      Select Case Cls.ToLower
        Case "death knight"
          res = ClassEnum.DeathKnight
        Case "druid"
          res = ClassEnum.Druid
        Case "hunter"
          res = ClassEnum.Hunter
        Case "mage"
          res = ClassEnum.Mage
        Case "paladin"
          res = ClassEnum.Paladin
        Case "priest"
          res = ClassEnum.Priest
        Case "rogue"
          res = ClassEnum.Rogue
        Case "shaman"
          res = ClassEnum.Shaman
        Case "warlock"
          res = ClassEnum.Warlock
        Case "warrior"
          res = ClassEnum.Warrior
        Case Else
          Throw New ClassNotValidException
      End Select
      Return res
    End Function

    Protected Shared Function GetGenderEnumFromString(ByVal Gender As String) As GenderEnum
      Dim res As GenderEnum
      Select Case Gender.ToLower
        Case "male"
          res = GenderEnum.Male
        Case "female"
          res = GenderEnum.Female
        Case Else
          Throw New GenderNotValidException
      End Select
      Return res
    End Function

    Protected Shared Function GetRaceEnumFromString(ByVal Race As String) As RaceEnum
      Dim res As RaceEnum
      Select Case Race.ToLower
        Case "blood elf"
          res = RaceEnum.BloodElf
        Case "draenei"
          res = RaceEnum.Draenei
        Case "dwarf"
          res = RaceEnum.Dwarf
        Case "gnome"
          res = RaceEnum.Gnome
        Case "human"
          res = RaceEnum.Human
        Case "night elf"
          res = RaceEnum.NightElf
        Case "orc"
          res = RaceEnum.Orc
        Case "tauren"
          res = RaceEnum.Tauren
        Case "troll"
          res = RaceEnum.Troll
        Case "undead"
          res = RaceEnum.Undead
        Case Else
          Throw New RaceNotValidException
      End Select
      Return res
    End Function

    Protected _Region As RegionEnum
  End Class
End Namespace